package com.sxj.corejava.code13_线程;

/**
 * @author 石小俊
 */
public class Test09_生产者消费者问题 {

    public static void main(String[] args) {
        ProductPool pool = new ProductPool();

        // 定义生产者线程，可以有无数个
        Producer p1 = new Producer(pool, "生产者p1");
        Producer p2 = new Producer(pool, "生产者p2");
        Producer p3 = new Producer(pool, "生产者p3");

        // 定义消费者线程，可以有无数个
        Consumer c1 = new Consumer(pool, "消费者c1");
        Consumer c2 = new Consumer(pool, "消费者c2");


        // 启动线程
        p1.start();
        p2.start();
        p3.start();
        c1.start();
        c2.start();
    }

}

/**
 * 商品缓冲区
 */
class ProductPool {
    // 当前缓冲区中商品的数量
    private int num;
    // 设置缓冲区商品上限
    private static final int MAX_COUNT = 10;

    /**
     * 生产商品
     * 生产者生产商品会向缓冲区中存放商品
     * 每调用一个生产方法，表示向缓冲区中存放一件商品
     * 即：商品缓冲区中数量+1
     *
     * @return
     */
    public int put() {
        // 每生产一次，数量+1
        return ++num;
    }

    /**
     * 消费者消费商品表示从缓冲区去拿取商品
     * 每调用一次消费方法，商品数量-1
     *
     * @return
     */
    public int get() {
        return --num;
    }

    /**
     * 判断当前缓冲区是否满了
     *
     * @return
     */
    public boolean isFull() {
        return this.num == MAX_COUNT;
    }

    /**
     * 判断当前缓冲区是否为空
     *
     * @return
     */
    public boolean isEmpty() {
        return this.num == 0;
    }
}

/**
 * 生产者线程
 */
class Producer extends Thread {
    private ProductPool pool;
    private String name;

    public Producer(ProductPool pool, String name) {
        this.pool = pool;
        this.name = name;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (pool) {
                // 判断是否需要生产
                // 当缓冲区商品数量达到上限，则不再生产，等待消费者进行消费
                if (pool.isFull()) {
                    try {
                        pool.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    // 如果缓冲区商品数量没有达到上限，则进行生产
                    int num = pool.put();
                    System.out.println(this.name + "生产了一件商品，当前缓冲区商品数量为:" + num);
                    // 当生产者进行生产之后，则缓冲区一定不为空，唤醒消费者进行消费
                    pool.notifyAll();
                }

            }
            try {
                Thread.sleep(600);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

/**
 * 消费者线程
 */
class Consumer extends Thread {
    private ProductPool pool;
    private String name;

    public Consumer(ProductPool pool, String name) {
        this.pool = pool;
        this.name = name;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (pool) {
                // 判断是否需要消费
                // 当缓冲区中商品为空时，不再消费，等待生产者进行生产
                if (pool.isEmpty()) {
                    try {
                        pool.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    // 如果缓冲区商品不为空，则进行消费
                    int num = pool.get();
                    System.out.println(this.name + "生产了一件商品，当前缓冲区商品数量为:" + num);
                    // 当消费者进行消费之后，缓冲区一定不满，唤醒生产者进行生产
                    pool.notifyAll();
                }
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}